#include "NetworkMessage.h"

NetworkMessage::NetworkMessage()
{
	Reset();
}

NetworkMessage::NetworkMessage(const NetworkMessage& msg)
{
	Reset();
	memcpy(Buffer, msg.Buffer, 32768);
	Length = msg.Length;
}

NetworkMessage::NetworkMessage(unsigned char* buf, int len)
{
	Reset();
	memcpy(Buffer, buf, len);
	Length = len;
}

NetworkMessage& NetworkMessage::operator =(const NetworkMessage& msg)
{
	Reset();
	memcpy(Buffer, msg.Buffer, 32768);
	Length = msg.Length;
	return *this;
}

bool NetworkMessage::CanAdd(int size)
{
	return (size + Length <= 32768);
}

bool NetworkMessage::WriteByte(unsigned char d)
{
	if (CanAdd(1))
	{
		Buffer[Length++] = d;
		return true;
	}
	return false;
}

bool NetworkMessage::WriteWord(unsigned short d)
{
	if (CanAdd(2))
	{
		WriteByte((unsigned char)(d & 0xFF));
		WriteByte((unsigned char)((d >> 8) & 0xFF));
		return true;
	}
	return false;
}

bool NetworkMessage::WriteDoubleWord(unsigned long d)
{
	if (CanAdd(4))
	{
		WriteWord((unsigned short)(d & 0xFFFF));
		WriteWord((unsigned short)((d >> 16) & 0xFFFF));
		return true;
	}
	return false;
}

bool NetworkMessage::WriteQuadWord(unsigned long long d)
{
	if (CanAdd(8))
	{
		WriteDoubleWord((unsigned long)(d & 0xFFFFFFFF));
		WriteDoubleWord((unsigned long)((d >> 32) & 0xFFFFFFFF));
		return true;
	}
	return false;
}

bool NetworkMessage::WriteRaw(const unsigned char* buffer, int length)
{
	if (CanAdd(length))
	{
		for (int i = 0; i < length; i++)
		{
			WriteByte(buffer[i]);
		}
		return true;
	}
	return false;
}

bool NetworkMessage::WriteString(std::string str)
{
	unsigned int len = str.length();
	if (len > 5120) // maximum string size
	{
		return false;
	}
	if (CanAdd(str.length() + 2))
	{
		WriteWord((unsigned short)(len));
		WriteRaw((unsigned char*)str.c_str(), len); // dont include NULL terminator
		return true;
	}
	return false;
}

unsigned char NetworkMessage::ReadByte()
{
	unsigned char d = 0;
	if (Length - Position >= 1)
	{
		d = Buffer[Position++];
	}
	return d;
}

unsigned short NetworkMessage::ReadWord()
{
	unsigned short d = 0;
	if (Length - Position >= 2)
	{
		d = (((unsigned short)ReadByte()) | (((unsigned short)ReadByte()) << 8));
	}
	return d;
}

unsigned long NetworkMessage::ReadDoubleWord()
{
	unsigned long d = 0;
	if (Length - Position >= 4)
	{
		d = (((unsigned long)ReadWord()) | (((unsigned long)ReadWord()) << 16));
	}
	return d;
}

unsigned long long NetworkMessage::ReadQuadWord()
{
	unsigned long long d = 0;
	if (Length - Position >= 8)
	{
		d = (((unsigned long long)ReadDoubleWord()) | (((unsigned long long)ReadDoubleWord()) << 32));
	}
	return d;
}

int NetworkMessage::ReadRaw(unsigned char* buffer, int length)
{
	if (Length - Position >= length)
	{
		for (int i = 0; i < length; i++)
		{
			buffer[i] = ReadByte();
		}
		return length;
	}
	return 0;
}

std::string NetworkMessage::ReadString()
{
	unsigned short len = ReadWord(); // read the length
	unsigned char buf[5120];
	std::string str = "";
	if (len > 0 && len < 5120)
	{
		memset(buf, 0, 5120);
		ReadRaw(buf, len);
		str = (char*)buf;
	}
	return str;
}

unsigned int NetworkMessage::GetLength()
{
	return Length;
}

void NetworkMessage::Reset()
{
	Position = Length = 0;
	memset(Buffer, 0, 32768);
}

NetworkMessage& NetworkMessage::Append(NetworkMessage& msg)
{
	WriteRaw(msg.Buffer, msg.Length);
	return *this;
}

int NetworkMessage::GetBuffer(unsigned char* out, int len)
{
	int size = (len < Length) ? len : Length;
	if (!out)
	{
		return 0;
	}
	memcpy(out, Buffer, size);
	return size;
}

void NetworkMessage::Copy(NetworkMessage& msg, int offset)
{
	int start = Position + offset;
	start = (start < 0) ? 0 : start; // make sure we start at the 1st element
	memcpy(msg.Buffer, &(Buffer[start]), Length - start);
	msg.Length = Length - start;
}